/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License");  you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * http//www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is SemanticTurkey.
 *
 * The Initial Developer of the Original Code is University of Roma Tor Vergata.
 * Portions created by University of Roma Tor Vergata are Copyright (C) 2007.
 * All Rights Reserved.
 *
 * SemanticTurkey was developed by the Artificial Intelligence Research Group
 * (art.uniroma2.it) at the University of Roma Tor Vergata (ART)
 * Current information about SemanticTurkey can be obtained at 
 * http://semanticturkey.uniroma2.it
 *
 */
package it.uniroma2.art.rangeannotator.osgi.service;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import it.uniroma2.art.owlart.exceptions.ModelAccessException;
import it.uniroma2.art.owlart.exceptions.ModelUpdateException;
import it.uniroma2.art.owlart.filter.ResourceOfATypePredicate;
import it.uniroma2.art.owlart.model.ARTLiteral;
import it.uniroma2.art.owlart.model.ARTResource;
import it.uniroma2.art.owlart.model.ARTURIResource;
import it.uniroma2.art.owlart.utilities.ModelUtilities;
import it.uniroma2.art.owlart.models.OWLModel;
import it.uniroma2.art.owlart.models.DirectReasoning;
import it.uniroma2.art.owlart.navigation.ARTLiteralIterator;
import it.uniroma2.art.owlart.navigation.ARTResourceIterator;
import it.uniroma2.art.owlart.utilities.DeletePropagationPropertyTree;
import it.uniroma2.art.owlart.vocabulary.VocabularyTypesEnum;
import it.uniroma2.art.semanticturkey.SemanticTurkeyOperations;
import it.uniroma2.art.semanticturkey.exceptions.HTTPParameterUnspecifiedException;
import it.uniroma2.art.semanticturkey.plugin.extpts.ServiceAdapter;
import it.uniroma2.art.semanticturkey.project.ProjectManager;
import it.uniroma2.art.semanticturkey.servlet.Response;
import it.uniroma2.art.semanticturkey.servlet.ResponseREPLY;
import it.uniroma2.art.semanticturkey.servlet.ServletUtilities;
import it.uniroma2.art.semanticturkey.servlet.ServiceVocabulary.RepliesStatus;
import it.uniroma2.art.semanticturkey.utilities.XMLHelp;
import it.uniroma2.art.semanticturkey.vocabulary.SemAnnotVocab;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.w3c.dom.Element;

public class RangeAnnotation extends ServiceAdapter {

	public static final String getPageAnnotationsRequest = "getPageAnnotations";
	public static final String chkAnnotationsRequest = "chkAnnotations";
	public static final String removeAnnotationRequest = "removeAnnotation";
	public static final String createAndAnnotateRequest = "createAndAnnotate";
	public static final String addAnnotationRequest = "addAnnotation";
	public static final String relateAndAnnotateRequest = "relateAndAnnotate";
	public static final String saveAnnotationsRequest = "saveAnnotations";
	// parameters
	public static final String urlPageString = "urlPage";
	public static final String titleString = "title";
	public static final String annotQNameString = "annotQName";
	public static final String annotIdString = "annotId";
	public static final String textString = "text";
	public static final String op = "op";

	public static final String clsQNameField = "clsQName";
	public static final String instanceQNameField = "instanceQName";
	public static final String objectClsNameField = "objectClsName";
	public static final String objectQNameField = "objectQName";
	public static final String urlPageField = "urlPage";
	public static final String titleField = "title";
	public static final String propertyQNameField = "propertyQName";
	public static final String langField = "lang";
	public static final String valueType = "type";
	public static final String rangeString = "range";

	// parameter values
	public static final String bindCreate = "bindCreate";
	public static final String bindAnnot = "bindAnnot";

	protected static Logger logger = LoggerFactory.getLogger(RangeAnnotation.class);

	protected ServletUtilities servletUtilities;
	protected DeletePropagationPropertyTree deletePropertyPropagationTreeForAnnotations;

	/**
	 * this service is in charge of managing range annotation actions over ontology resources
	 * 
	 * @param id
	 */

	public RangeAnnotation(String id) {
		super(id);
		servletUtilities = ServletUtilities.getService();
	}

	protected void initializeDeletePropertyPropagationTreeForAnnotations() {
		deletePropertyPropagationTreeForAnnotations = new DeletePropagationPropertyTree();
		deletePropertyPropagationTreeForAnnotations.addChild(SemAnnotVocab.Res.annotation).addChild(
				SemAnnotVocab.Res.location);
		deletePropertyPropagationTreeForAnnotations.addChild(SemAnnotVocab.Res.annotation).addChild(
				SemAnnotVocab.Res.location).addChild(SemAnnotVocab.Res.range);

	}

	public Response getResponse() {
		Response response = null;
		String request = setHttpPar("request");
		try {
			if (request.equals(getPageAnnotationsRequest)) {
				String urlPage = setHttpPar(urlPageString);
				response = getPageRangeAnnotations(urlPage);
			} else if (request.equals(chkAnnotationsRequest)) {
				String urlPage = setHttpPar(urlPageString);
				checkRequestParametersAllNotNull(urlPageString);
				response = chkPageForRangeAnnotations(urlPage);
			} else if (request.equals(removeAnnotationRequest)) {
				String annotQName = setHttpPar(annotQNameString);
				String annotId = setHttpPar(annotIdString);
				response = removeRangeAnnotation(annotQName, annotId);
			} else if (request.equals(createAndAnnotateRequest)) {
				String clsQName = setHttpPar(clsQNameField);
				String instanceNameEncoded = servletUtilities.encodeLabel(setHttpPar(instanceQNameField));
				String range = setHttpPar(rangeString);
				String urlPage = setHttpPar(urlPageString);
				String title = setHttpPar(titleString);
				response = dragDropSelectionOverClass(instanceNameEncoded, clsQName, urlPage, title, range);
			} else if (request.equals(addAnnotationRequest)) {
				String urlPage = setHttpPar(urlPageString);
				String instanceQName = setHttpPar(instanceQNameField);
				String text = setHttpPar(textString);
				String range = setHttpPar(rangeString);
				String textEncoded = servletUtilities.encodeLabel(text);
				String title = setHttpPar(titleString);
				response = annotateInstanceWithDragAndDrop(instanceQName, textEncoded, urlPage, title, range);
			} else if (request.equals(saveAnnotationsRequest)) {
				String outPutFile = setHttpPar("file");
				return saveAnnotations(new File(outPutFile));
			} else if (request.equals(relateAndAnnotateRequest)) {
				String subjectInstanceQName = setHttpPar(instanceQNameField);
				String predicatePropertyName = setHttpPar(propertyQNameField);
				String objectInstanceName = setHttpPar(objectQNameField);
				String objectInstanceNameEncoded = servletUtilities.encodeLabel(objectInstanceName);
				String urlPage = setHttpPar(urlPageField);
				String title = setHttpPar(titleField);
				String op = setHttpPar("op");
				String range = setHttpPar(rangeString);
				String valueTypeStr = setHttpPar(valueType);
				VocabularyTypesEnum type = (valueTypeStr == null) ? null : VocabularyTypesEnum
						.valueOf(valueTypeStr);
				if (op.equals("bindCreate")) {
					String rangeClsName = setHttpPar(objectClsNameField);
					String lang = setHttpPar(langField);
					return bindAnnotatedObjectToNewInstanceAndRelateToDroppedInstance(subjectInstanceQName,
							predicatePropertyName, objectInstanceNameEncoded, type, rangeClsName, urlPage,
							title, range, lang);
				}

				// httpGet2("http://127.0.0.1:1979/semantic_turkey/resources/stserver/STServer?service=property&instanceQName=University%20of%20Rome%20%22Tor%20Vergata%22&propertyQName=filas:worksInCompany&objectQName=[object%20XULElement]&lexicalization=%22Tor%20Vergata%22&urlPage=http://ai-nlp.info.uniroma2.it/zanzotto/short_bio.html&title=Enrichment%20Property&op=annot
				// httpGet2("http://127.0.0.1:1979/semantic_turkey/resources/stserver/STServer?service=property&instanceQName="
				// + subjectInstanceName + "&propertyQName=" +predicatePropertyName+"&objectQName=" +
				// objectInstanceName + "&lexicalization=" + objectInstanceName +"&urlPage=" +
				// window.arguments[0].urlPage + "&title=" + title+"&op=annot", false);
				if (op.equals("bindAnnot")) {
					String annotation = setHttpPar("lexicalization");
					return addNewAnnotationForSelectedInstanceAndRelateToDroppedInstance(
							subjectInstanceQName, predicatePropertyName, objectInstanceNameEncoded,
							annotation, urlPage, title, range);
				}

				// 
			}
		} catch (HTTPParameterUnspecifiedException e) {
			return ServletUtilities.getService().createUndefinedHttpParameterExceptionResponse(request, e);
		} catch (ModelAccessException e) {
			return ServletUtilities.getService().createExceptionResponse(request, e);
		}

		this.fireServletEvent();
		return response;
	}

	/**
	 * this service returns all previous range annotations taken into the page associated to the given url
	 * 
	 * <Tree type="RangeAnnotations"> <RangeAnnotation id="04282b25-2f32-421e-8418-9317e3ef8553"
	 * resource="Armando Stellato" value="Armando Stellato" range=""/> <Annotation
	 * id="57a6c560-e1e4-4f3a-a1ba-00fc874e1c71" resource="Marco Pennacchiotti" value="Marco Pennacchiotti"
	 * range=""/> <Annotation id="86398074-bb67-4986-86df-bcb8b414a91a"
	 * resource="University of Rome, Tor Vergata" value="University of Rome, Tor Vergata" range=""/> </Tree>
	 * 
	 * @param urlPage
	 *            the url of the page which is searched for existing annotations
	 * @return
	 */
	public Response getPageRangeAnnotations(String urlPage) {
		OWLModel ontModel = (OWLModel) ProjectManager.getCurrentProject().getOntModel();
		ServletUtilities servletUtilities = ServletUtilities.getService();

		ResponseREPLY response = servletUtilities.createReplyResponse(getPageAnnotationsRequest,
				RepliesStatus.ok);

		Element dataElement = response.getDataElement();

		ARTLiteral urlPageLiteral = ontModel.createLiteral(urlPage);
		ARTResourceIterator collectionIterator;
		ARTResource webPage = null;
		ResourceOfATypePredicate rangeAnnotationPredicate = ResourceOfATypePredicate.getPredicate(ontModel,
				SemAnnotVocab.Res.RangeAnnotation);
		try {
			collectionIterator = ontModel.listSubjectsOfPredObjPair(SemAnnotVocab.Res.url, urlPageLiteral,
					true);
			while (collectionIterator.hasNext()) {
				webPage = (ARTResource) collectionIterator.next();
			}
			if (webPage == null) {
				return response;
			}
		} catch (ModelAccessException e) {
			return servletUtilities.createExceptionResponse(getPageAnnotationsRequest, e);
		}

		ARTResourceIterator semanticAnnotationsIterator;
		try {
			semanticAnnotationsIterator = ontModel.listSubjectsOfPredObjPair(SemAnnotVocab.Res.location,
					webPage, true);
			while (semanticAnnotationsIterator.streamOpen()) {
				ARTResource semanticAnnotation = semanticAnnotationsIterator.getNext().asURIResource();
				ARTLiteralIterator lexicalizationIterator = ontModel.listValuesOfSubjDTypePropertyPair(
						semanticAnnotation, SemAnnotVocab.Res.text, true);
				ARTLiteral lexicalization = lexicalizationIterator.getNext(); // there is at least one and no
				// more than one lexicalization
				// for each semantic annotation
				if (rangeAnnotationPredicate.apply(semanticAnnotation)) {
					Element annotationElement = XMLHelp.newElement(dataElement, "RangeAnnotation");
					annotationElement.setAttribute("id", ontModel.getQName(semanticAnnotation.asURIResource()
							.getURI()));
					annotationElement.setAttribute("value", lexicalization.getLabel());
					ARTURIResource annotatedResource = ontModel.listSubjectsOfPredObjPair(
							SemAnnotVocab.Res.annotation, semanticAnnotation, true).getNext().asURIResource();
					// there is at least one and no more than one referenced resource for each semantic
					// annotation
					annotationElement.setAttribute("resource", ontModel.getQName(annotatedResource.getURI()));
					ARTLiteral range = ontModel.listValuesOfSubjDTypePropertyPair(semanticAnnotation,
							SemAnnotVocab.Res.range, true).getNext();
					annotationElement.setAttribute("range", range.getLabel());
				}
			}
		} catch (ModelAccessException e) {
			return servletUtilities.createExceptionResponse(getPageAnnotationsRequest, e);
		}

		return response;
	}

	/**
	 * informs the client if the requested page contains RangeAnnotations
	 * 
	 * <Tree type="Ack" request="chkRangeAnnotations"> <result status="yes"/> //or "no" </Tree>
	 * 
	 * @param urlPage
	 * @return
	 */
	public Response chkPageForRangeAnnotations(String urlPage) {
		String request = chkAnnotationsRequest;
		OWLModel ontModel = ProjectManager.getCurrentProject().getOntModel();

		ARTLiteral urlPageLiteral = ontModel.createLiteral(urlPage);
		ARTResourceIterator collectionIterator;
		try {
			collectionIterator = ontModel.listSubjectsOfPredObjPair(SemAnnotVocab.Res.url, urlPageLiteral,
					true);
			// this predicate filters out annotations which are not RangeAnnotations
			ResourceOfATypePredicate rangeAnnotationPredicate = ResourceOfATypePredicate.getPredicate(
					ontModel, SemAnnotVocab.Res.RangeAnnotation);
			boolean rangeAnnotationFound = false;
			while (collectionIterator.hasNext()) {
				if (rangeAnnotationPredicate.apply((ARTResource) collectionIterator.next())) {
					rangeAnnotationFound = true;
					break;
				}
			}
			RepliesStatus reply;

			if (rangeAnnotationFound)
				reply = RepliesStatus.ok;
			else
				reply = RepliesStatus.fail;
			return ServletUtilities.getService().createReplyResponse(request, reply);

		} catch (ModelAccessException e) {
			return ServletUtilities.getService().createExceptionResponse(chkAnnotationsRequest, e);
		}

	}

	/**
	 * tells the server to remove an annotation; the answer informs the client of the success of this removal
	 * identical implementation of its ancestor method, though a different header is returned in the response
	 * XML tree
	 * 
	 * <Tree type="Ack" request="removeRangeAnnotation"> <result status="yes"/> //or "no" </Tree>
	 * 
	 * @param annotQName
	 * @return
	 */
	public Response removeRangeAnnotation(String annotQName, String id) {

		String request = removeAnnotationRequest;
		logger.debug("replying to \"removeAnnotation(" + annotQName + ")\".");
		OWLModel ontModel = ProjectManager.getCurrentProject().getOntModel();

		ARTURIResource annot;
		// ARTURIResource annotId;

		try {
			annot = ontModel.createURIResource(ontModel.expandQName(annotQName));
			if (annot == null)
				return servletUtilities.createExceptionResponse(request,
						"selected annotation is not present in the ontology");

			if (deletePropertyPropagationTreeForAnnotations == null)
				initializeDeletePropertyPropagationTreeForAnnotations();
			ModelUtilities.deepDeleteIndividual(annot, ontModel, deletePropertyPropagationTreeForAnnotations);

			return ServletUtilities.getService().createReplyResponse(request, RepliesStatus.ok, null);

		} catch (ModelAccessException mae) {
			return servletUtilities.createExceptionResponse(request, mae);
		} catch (ModelUpdateException mue) {
			return servletUtilities.createExceptionResponse(request, mue);
		}

	}

	/**
	 * creates an instance with associated annotation from the current web page note that the parameter
	 * instanceQName is handled like a Qname, but it is the selection dragged from the web browser
	 * 
	 * @return
	 */
	public Response dragDropSelectionOverClass(String instanceQName, String clsQName, String urlPage,
			String title, String range) {
		ServletUtilities servletUtilities = ServletUtilities.getService();
		logger.debug("dragged: " + instanceQName + " over class: " + clsQName + " on url: " + urlPage
				+ " with title: " + title);
		String handledUrlPage = urlPage.replace(":", "%3A");
		handledUrlPage = handledUrlPage.replace("/", "%2F");
		OWLModel ontModel = ProjectManager.getCurrentProject().getOntModel();
		try {
			String instanceURI = ontModel.expandQName(instanceQName);
			ARTURIResource instanceRes = ontModel.retrieveURIResource(instanceURI);
			if (instanceRes != null)
				return servletUtilities.createExceptionResponse(createAndAnnotateRequest,
						"there is another resource with the same name!");

			ARTURIResource cls = ontModel.createURIResource(ontModel.expandQName(clsQName));
			ontModel.addInstance(instanceURI, cls);
			ARTResource webPageInstance = SemanticTurkeyOperations.createWebPage(ontModel, urlPage, title);
			logger.debug("creating Semantic Annotation for: instQName: " + instanceQName
					+ " lexicalization: " + instanceQName + " webPageInstance " + webPageInstance
					+ " range: " + range);
			createRangeLexicalization(ontModel, instanceQName, instanceQName, urlPage, title, range);

		} catch (ModelUpdateException e) {
			logger.error("instance creation error", e);
			return servletUtilities.createExceptionResponse(createAndAnnotateRequest,
					"instance creation error: " + e.getMessage());
		} catch (ModelAccessException e) {
			return servletUtilities.createExceptionResponse(createAndAnnotateRequest, e);
		}

		return updateClassOnTree(clsQName, instanceQName);

	}

	// TODO this is the copy of the same method present in the Cls servlet. Factorize it somehow
	/**
	 * @param clsQName
	 * @param instanceName
	 * @return
	 */
	public Response updateClassOnTree(String clsQName, String instanceName) {
		ServletUtilities servletUtilities = new ServletUtilities();
		ResponseREPLY response = servletUtilities.createReplyResponse(createAndAnnotateRequest,
				RepliesStatus.ok);
		Element dataElement = response.getDataElement();

		OWLModel ontModel = ProjectManager.getCurrentProject().getOntModel();
		Element clsElement = XMLHelp.newElement(dataElement, "Class");

		clsElement.setAttribute("clsName", clsQName);
		try {
			clsQName = ontModel.expandQName(clsQName);
		} catch (ModelAccessException e1) {

			e1.printStackTrace();
		}
		ARTResource cls = ontModel.createURIResource(clsQName);
		String numTotInst;
		try {
			numTotInst = ""
					+ ModelUtilities.getNumberOfClassInstances(((DirectReasoning) ontModel), cls, true);
			clsElement.setAttribute("numTotInst", numTotInst);
		} catch (ModelAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		Element instanceElement = XMLHelp.newElement(dataElement, "Instance");
		instanceElement.setAttribute("instanceName", servletUtilities.decodeLabel(instanceName));
		return response;
	}

	/**
	 * invoked when the user drags text over an instance of the ontology. An individual for that class is
	 * created and a semantic bookmark is registered for that individual in the browsed page
	 * 
	 * @param subjectInstanceQName
	 * @param lexicalizationEncoded
	 * @param urlPage
	 * @param title
	 * @param range
	 * @return
	 */
	public Response annotateInstanceWithDragAndDrop(String subjectInstanceQName,
			String lexicalizationEncoded, String urlPage, String title, String range) {
		logger.debug("taking annotation for: url" + urlPage + " instanceQName: " + subjectInstanceQName
				+ " lexicalization: " + lexicalizationEncoded + " title: " + title);
		ServletUtilities servletUtilities = new ServletUtilities();
		OWLModel ontModel = ProjectManager.getCurrentProject().getOntModel();
		try {
			// ARTResource webPageInstance = createWebPage(ontModel, urlPage, title);
			// logger.debug("creating Semantic Annotation for: instQName: " + subjectInstanceQName +
			// " lexicalization: "
			// + encodedText + " webPageInstance " + webPageInstance + " range: "+range);
			createRangeLexicalization(ontModel, subjectInstanceQName, lexicalizationEncoded, urlPage, title,
					range);
		} catch (ModelUpdateException e) {
			logger.error("lexicalization creation error: ", e);
			return servletUtilities.createExceptionResponse(addAnnotationRequest,
					"lexicalization creation error: " + e.getMessage());
		} catch (ModelAccessException e) {
			logger.error("lexicalization creation error: ", e);
			return servletUtilities.createExceptionResponse(addAnnotationRequest,
					"lexicalization creation error: " + e.getMessage());
		}
		logger.debug("annotation taken");
		return servletUtilities.createReplyResponse(addAnnotationRequest, RepliesStatus.ok);
	}

	/**
	 * @author NScarpato Metodo che crea una lessicalizzazione di instanceName e gli associa un'istanza di
	 *         WebPage con valore urlPage e invoca createSemanticAnnotation
	 * 
	 * @param SesameARTRepositoryImpl
	 *            repository
	 *@param String
	 *            instanceQName
	 *@param String
	 *            lexicalization
	 *@param String
	 *            pageURL
	 *@param String
	 *            title
	 * @throws ModelUpdateException
	 * @throws ModelAccessException
	 */

	public static void createRangeLexicalization(OWLModel repository, String instanceQName,
			String lexicalization, String pageURL, String title, String range) throws ModelUpdateException,
			ModelAccessException {
		logger.debug("creating lexicalization: " + lexicalization + " for instance: " + instanceQName
				+ " on url: " + pageURL + " with title: " + title);

		ARTResource webPageInstance = SemanticTurkeyOperations.createWebPage(repository, pageURL, title);
		logger.debug("creating Semantic Annotation for: instQName: " + instanceQName + " lexicalization: "
				+ lexicalization + " webPageInstance " + webPageInstance);
		createSemanticRangeAnnotation(repository, instanceQName, lexicalization, webPageInstance, range);
	}

	/**
	 * Metodo che crea una istanza di SemanticRangeAnnotation associando una lexicalization all'istanza della
	 * classe
	 * 
	 * @param SesameOWLModelImpl
	 *            repository
	 *@param String
	 *            instanceName
	 *@param String
	 *            lexicalization
	 *@param String
	 *            webPageInstanceName
	 *@param String
	 *            range
	 * @throws ModelUpdateException
	 * @throws ModelAccessException
	 **/
	private static void createSemanticRangeAnnotation(OWLModel repository, String individualQName,
			String lexicalization, ARTResource webPageInstanceRes, String range) throws ModelUpdateException,
			ModelAccessException {

		String semanticAnnotationID = SemanticTurkeyOperations.generateNewSemanticAnnotationUUID(repository);

		repository.addInstance(repository.getDefaultNamespace() + semanticAnnotationID,
				SemAnnotVocab.Res.RangeAnnotation);

		ARTResource semanticAnnotationInstanceRes = repository.createURIResource(repository
				.getDefaultNamespace()
				+ semanticAnnotationID);
		logger.debug("creating lexicalization: semAnnotInstanceRes: " + semanticAnnotationInstanceRes + "");
		repository.instantiateDatatypeProperty(semanticAnnotationInstanceRes, SemAnnotVocab.Res.text,
				lexicalization);

		repository.instantiateObjectProperty(semanticAnnotationInstanceRes, SemAnnotVocab.Res.location,
				webPageInstanceRes);
		repository.instantiateDatatypeProperty(semanticAnnotationInstanceRes, SemAnnotVocab.Res.range, range);

		ARTResource instanceRes;
		try {
			instanceRes = repository.createURIResource(repository.expandQName(individualQName));
		} catch (ModelAccessException e) {
			throw new ModelUpdateException(e);
		}
		repository.instantiateObjectProperty(instanceRes, SemAnnotVocab.Res.annotation,
				semanticAnnotationInstanceRes);
	}

	public Response saveAnnotations(File file) throws ModelAccessException {
		OWLModel ontModel = (OWLModel) ProjectManager.getCurrentProject().getOntModel();
		ServletUtilities servletUtilities = ServletUtilities.getService();

		ResponseREPLY response = servletUtilities.createReplyResponse(saveAnnotationsRequest,
				RepliesStatus.ok);

		Element dataElement = response.getDataElement();
		ARTResourceIterator webPageIterator = ontModel.listInstances(SemAnnotVocab.Res.WebPage, true);
		
		while (webPageIterator.hasNext()) {
			ARTResource urlPage = webPageIterator.next();
			logger.debug("Web page"+urlPage);
			Element webPageElement = XMLHelp.newElement(dataElement, "WebPage"); 
			String url = ontModel.listValuesOfSubjDTypePropertyPair(urlPage, SemAnnotVocab.Res.url, true).getNext().getLabel();
			webPageElement.setAttribute("url", url); 
			ARTLiteral urlPageLiteral = ontModel.createLiteral(url);
			ARTResourceIterator collectionIterator;
			ARTResource webPage = null;
			ResourceOfATypePredicate rangeAnnotationPredicate = ResourceOfATypePredicate.getPredicate(
					ontModel, SemAnnotVocab.Res.RangeAnnotation);
			try {
				collectionIterator = ontModel.listSubjectsOfPredObjPair(SemAnnotVocab.Res.url, urlPageLiteral, true);
				while (collectionIterator.hasNext()) {
					webPage = (ARTResource) collectionIterator.next();
				}
				if (webPage == null) {
					return response;
				}
			} catch (ModelAccessException e) {
				return servletUtilities.createExceptionResponse(saveAnnotationsRequest, e);
			}
			
			ARTResourceIterator semanticAnnotationsIterator;
			try {
				semanticAnnotationsIterator = ontModel.listSubjectsOfPredObjPair(SemAnnotVocab.Res.location,
						webPage, true);
				
				while (semanticAnnotationsIterator.streamOpen()) {
					ARTResource semanticAnnotation = semanticAnnotationsIterator.getNext().asURIResource();
					ARTLiteralIterator lexicalizationIterator = ontModel.listValuesOfSubjDTypePropertyPair(
							semanticAnnotation, SemAnnotVocab.Res.text, true);
					ARTLiteral lexicalization = lexicalizationIterator.getNext(); // there is at least one and
																					// no
					// more than one lexicalization
					// for each semantic annotation
					if (rangeAnnotationPredicate.apply(semanticAnnotation)) {
						Element annotationElement = XMLHelp.newElement(webPageElement, "RangeAnnotation");
						annotationElement.setAttribute("id", ontModel.getQName(semanticAnnotation
								.asURIResource().getURI()));
						annotationElement.setAttribute("value", lexicalization.getLabel());
						ARTURIResource annotatedResource = ontModel.listSubjectsOfPredObjPair(
								SemAnnotVocab.Res.annotation, semanticAnnotation, true).getNext()
								.asURIResource();
						// there is at least one and no more than one referenced resource for each semantic
						// annotation
						annotationElement.setAttribute("resource", ontModel.getQName(annotatedResource
								.getURI()));
						ARTLiteral range = ontModel.listValuesOfSubjDTypePropertyPair(semanticAnnotation,
								SemAnnotVocab.Res.range, true).getNext();
						annotationElement.setAttribute("range", range.getLabel());
					}
				}
				
			} catch (ModelAccessException e) {
				return servletUtilities.createExceptionResponse(saveAnnotationsRequest, e);
			}
		}// fine while
		
		try {
			BufferedWriter out = new BufferedWriter(new FileWriter(file));
			out.write(XMLHelp.XML2String(dataElement, true));
			out.close();
			System.out.println(dataElement);
		} catch (IOException e) {
			return servletUtilities.createErrorResponse(saveAnnotationsRequest, e.getMessage());
		}
		return response;
	}

	/**
	 * invoked when the user annotates new text which is dragged upon an individual to create a new individual
	 * which is bound to the first one through a given property
	 * 
	 * <Tree type="bindAnnotToNewInstance"> <Class clsName="rtv:Organization" numTotInst="1"/> <Instance
	 * instanceName="University of Rome, Tor Vergata"/> </Tree>
	 * 
	 * @param subjectInstanceQName
	 * @param predicatePropertyQName
	 * @param objectInstanceQName
	 * @param rangeClsQName
	 * @param urlPage
	 * @param title
	 * @return
	 */
	public Response bindAnnotatedObjectToNewInstanceAndRelateToDroppedInstance(String subjectInstanceQName,
			String predicatePropertyQName, String objectInstanceQName, VocabularyTypesEnum type,
			String rangeClsQName, String urlPage, String title, String range, String lang) {
		ServletUtilities servletUtilities = new ServletUtilities();
		OWLModel ontModel = ProjectManager.getCurrentProject().getOntModel();
		ARTURIResource property;

		try {
			property = ontModel.createURIResource(ontModel.expandQName(predicatePropertyQName));
			ARTResource rangeClsRes = null;

			if (ontModel.isDatatypeProperty(property) || ontModel.isAnnotationProperty(property)
					|| type == VocabularyTypesEnum.literal) {
				logger.debug("adding value to a literal valued property ");
				ARTURIResource subjectInstanceEncodedRes = ontModel.createURIResource(ontModel
						.expandQName(subjectInstanceQName));
				try {
					if (ontModel.isAnnotationProperty(property)) {
						logger.debug("adding value" + objectInstanceQName
								+ "to annotation property with lang: ");
						ontModel.instantiateAnnotationProperty(subjectInstanceEncodedRes, property,
								objectInstanceQName, lang);
					} else { // Datatype or simple property
						logger.debug("adding value" + objectInstanceQName + "to datatype property");
						ontModel.instantiateDatatypeProperty(subjectInstanceEncodedRes, property,
								objectInstanceQName);
					}
				} catch (ModelUpdateException e) {
					logger.error("literal creation error: " + e.getMessage(), e);
					return servletUtilities.createExceptionResponse(relateAndAnnotateRequest,
							"literal creation error: " + e.getMessage());
				}
			} else {
				String rangeClsURI = ontModel.expandQName(rangeClsQName);
				logger.debug("rangeClsQName: " + rangeClsQName + " uri: " + rangeClsURI);
				rangeClsRes = ontModel.createURIResource(rangeClsURI);
				if (rangeClsRes == null) {
					logger.debug("there is no class named: " + rangeClsURI + " !");
					return servletUtilities.createExceptionResponse(relateAndAnnotateRequest,
							"there is no class named: " + rangeClsURI + " !");
				}

				try {
					ontModel.addInstance(ontModel.expandQName(objectInstanceQName), rangeClsRes);
					// ARTResource webPageInstance = createWebPage(ontModel, urlPage, title);
					// createRangeLexicalization(ontModel, objectInstanceQName, objectInstanceQName, urlPage,
					// range);

				} catch (ModelUpdateException e) {
					logger.error("Instance creation error: ", e);
					return servletUtilities.createExceptionResponse(relateAndAnnotateRequest,
							"Instance creation error: " + e.getMessage());
				}

				ARTURIResource objectInstanceRes = ontModel.createURIResource(ontModel
						.expandQName(objectInstanceQName));
				ARTURIResource subjectInstanceRes = ontModel.createURIResource(ontModel
						.expandQName(subjectInstanceQName));
				ontModel.instantiateObjectProperty(subjectInstanceRes, property, objectInstanceRes);
				logger.debug("property: " + property + " istantiated with value: " + objectInstanceRes
						+ " on subject: " + subjectInstanceRes + "with range " + range);
			}

			ResponseREPLY response = servletUtilities.createReplyResponse(relateAndAnnotateRequest,
					RepliesStatus.ok);
			Element dataElement = response.getDataElement();
			dataElement.setAttribute("op", "bindAnnotToNewInstance");
			// NScarpato 27/05/2007 add numTotInst attribute (TODO rimuoverlo dopo aver controllato che non
			// serva da nessuna parte)
			if (rangeClsRes != null) {
				Element clsElement = XMLHelp.newElement(dataElement, "Class");
				clsElement.setAttribute("clsName", rangeClsQName);
				ARTResourceIterator it = ((DirectReasoning) ontModel).listDirectInstances(rangeClsRes);
				int instCounter = 0;
				while (it.streamOpen()) {
					instCounter++;
					it.getNext();
				}
				clsElement.setAttribute("numTotInst", "" + instCounter);
			}
			Element instanceElement = XMLHelp.newElement(dataElement, "Instance");
			instanceElement.setAttribute("instanceName", servletUtilities.decodeLabel(objectInstanceQName));
			return response;

		} catch (ModelAccessException e) {
			return ServletUtilities.getService().createExceptionResponse(relateAndAnnotateRequest, e);
		} catch (ModelUpdateException e) {
			return ServletUtilities.getService().createExceptionResponse(relateAndAnnotateRequest, e);
		}
	}

	public Response addNewAnnotationForSelectedInstanceAndRelateToDroppedInstance(
			String subjectInstanceQName, String predicatePropertyQName, String objectInstanceQName,
			String lexicalization, String urlPage, String title, String range) {
		ServletUtilities servletUtilities = new ServletUtilities();
		OWLModel ontModel = ProjectManager.getCurrentProject().getOntModel();

		try {
			ARTURIResource property = ontModel
					.createURIResource(ontModel.expandQName(predicatePropertyQName));
			ARTResource webPageInstance = SemanticTurkeyOperations.createWebPage(ontModel, urlPage, title);

			createSemanticRangeAnnotation(ontModel, objectInstanceQName, lexicalization, webPageInstance,
					range);
			ARTResource subjectInstanceRes = ontModel.createURIResource(ontModel
					.expandQName(subjectInstanceQName));
			ARTResource objectInstanceRes = ontModel.createURIResource(ontModel
					.expandQName(objectInstanceQName));
			ontModel.instantiateObjectProperty(subjectInstanceRes, property, objectInstanceRes);
		} catch (ModelUpdateException e) {
			logger.error("Instance creation error: ", e);
			return servletUtilities.createExceptionResponse(relateAndAnnotateRequest,
					"Instance creation error: " + e.getMessage());
		} catch (ModelAccessException e) {
			logger.error("Ontology Access error: ", e);
			return servletUtilities.createExceptionResponse(relateAndAnnotateRequest,
					"Ontology Access error: " + e.getMessage());
		}

		return servletUtilities.createReplyResponse(relateAndAnnotateRequest, RepliesStatus.ok, null);

	}
}
